package org.cerberus.platform.internal;

import org.cerberus.platform.internal.domain.IComponentClass;
import org.cerberus.platform.internal.impl.ComponentClassException;

/**
 * The implementation of {@link IPlatformClassLoader} is the central handler of
 * class definitions in the platform. It is able to define classes depending
 * their annotations and validate them. It also implements instance count
 * tracking of each class and frees classes if they are not referenced anymore.
 * 
 * You are able not to use instance count tracking if you simple never call
 * {@link #increment(IComponentClass, LoaderCallback)} or
 * {@link #decrement(IComponentClass, UnLoaderCallback)}. If they are not 
 * called their classes may not be freed.
 * 
 * @author Christian Humer
 * @since 2.0
 */
public interface IPlatformClassLoader {

	/**
	 * Loads the class according to their class configuration (annotations) and
	 * invokes the loaderCallback if additional classes may be loaded. If the
	 * class is already defined it returns the currently tracked instance. The
	 * callback parameter must not be null.
	 * 
	 * @param clazz
	 *            the java class to define
	 * @param callback
	 *            the call back to call
	 * @throws ComponentClassException
	 *             if class definition is not valid
	 * @return the component class definition
	 */
	public IComponentClass defineClass(Class<?> clazz, LoaderCallback callback);
	
	/**
	 * Notifies the classloader that one more instance is referenced. This may
	 * prevent the {@link #decrement(IComponentClass, UnLoaderCallback)} method
	 * for releasing this class.
	 * 
	 * @param clazz
	 *            the component class to increment
	 * @param callback
	 *            must not be null
	 */
	public void increment(IComponentClass clazz, LoaderCallback callback);
	
	/**
	 * Notifies the classloader that one less instance of this type is
	 * references. This may lead to the case that the component class is removed
	 * from class loader. This is only possible if the component class is not
	 * referenced by another instance.
	 * 
	 * @param clazz
	 *            the class to decrement
	 * @param callback
	 *            must not be null
	 */
	public void decrement(IComponentClass clazz, UnLoaderCallback callback);
	
	/**
	 * Returns true if the class is already loaded, otherwise false.
	 * 
	 * @param clazz
	 *            the class to check.
	 * @return true if loaded false if not.
	 */
	public boolean isLoaded(Class<?> clazz);
	
	public static interface UnLoaderCallback {
		
		/**
		 * Will be called when a class is unloaded (removed) from classloader.
		 * 
		 * @param clazz
		 *            the class that is unloaded
		 */
		void unloaded(IComponentClass clazz);
	}
	
	public static interface LoaderCallback {
		
		/**
		 * Will e called when a class is loaded (added) to classloader.
		 * 
		 * @param clazz
		 *            the class that is loaded
		 */
		void loaded(IComponentClass clazz);
	}
	
}
